package com.example.micro_property_springboot.aspect;

import com.example.micro_property_springboot.pojo.SysOperLog;
import com.example.micro_property_springboot.service.SysOperLogService;
import com.example.micro_property_springboot.utils.HttpContextUtils;
import com.example.micro_property_springboot.utils.IpUtils;
import com.example.micro_property_springboot.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 操作日志记录AOP切面
 * 使用AspectJ实现非侵入式的操作日志记录
 */
@Slf4j
@Aspect
@Component
public class OperLogAspect {
    
    @Autowired
    private SysOperLogService sysOperLogService;
    
    /**
     * 定义切点 - 拦截所有Controller方法
     */
    @Pointcut("execution(* com.example.micro_property_springboot.controller.*.*(..))")
    public void operLogPointCut() {
    }
    
    /**
     * 正常返回通知
     */
    @AfterReturning(pointcut = "operLogPointCut()", returning = "result")
    public void saveOperLog(JoinPoint joinPoint, Object result) {
        try {
            // 1. 获取请求相关信息
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            
            // 2. 创建操作日志实体
            SysOperLog operLog = new SysOperLog();
            
            // 3. 设置日志基本信息
            operLog.setOperIp(IpUtils.getIpAddr(request));
            operLog.setOperTime(LocalDateTime.now());
            
            // 4. 获取操作用户信息
            try {
                operLog.setUserId(SecurityUtils.getCurrentUserId());
            } catch (Exception e) {
                operLog.setUserId(0L);
            }
            
            // 5. 获取方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            
            // 6. 设置操作模块和操作类型（从方法名或注解中提取）
            operLog.setOperModule(getModuleName(method));
            operLog.setOperType(getOperType(method));
            
            // 7. 获取请求参数
            Map<String, String[]> paramMap = request.getParameterMap();
            StringBuilder params = new StringBuilder();
            for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
                params.append(entry.getKey()).append(":").append(String.join(",", entry.getValue())).append(", ");
            }
            // 8. 保存日志
            sysOperLogService.save(operLog);
            
        } catch (Exception e) {
            log.error("记录操作日志失败：", e);
        }
    }
    
    /**
     * 异常通知
     */
    @AfterThrowing(pointcut = "operLogPointCut()", throwing = "e")
    public void saveExceptionLog(JoinPoint joinPoint, Exception e) {
        try {
            // 1. 获取请求相关信息
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            
            // 2. 创建操作日志实体
            SysOperLog operLog = new SysOperLog();
            
            // 3. 设置日志基本信息
            operLog.setOperIp(IpUtils.getIpAddr(request));
            operLog.setOperTime(LocalDateTime.now());
            
            // 4. 获取操作用户信息
            try {
                operLog.setUserId(SecurityUtils.getCurrentUserId());
            } catch (Exception ex) {
                operLog.setUserId(0L);
            }
            
            // 5. 获取方法信息
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            
            // 6. 设置操作模块和操作类型
            operLog.setOperModule(getModuleName(method));
            operLog.setOperType(getOperType(method));
            
            // 7. 保存日志
            sysOperLogService.save(operLog);
            
        } catch (Exception ex) {
            log.error("记录异常日志失败：", ex);
        }
    }
    
    /**
     * 根据方法名获取模块名
     */
    private String getModuleName(Method method) {
        // 这里可以从注解中获取，或者根据方法名推断
        String className = method.getDeclaringClass().getSimpleName();
        return className.replace("Controller", "");
    }
    
    /**
     * 根据方法名获取操作类型
     */
    private String getOperType(Method method) {
        String methodName = method.getName();
        if (methodName.startsWith("add") || methodName.startsWith("create") || methodName.startsWith("insert")) {
            return "新增";
        } else if (methodName.startsWith("update") || methodName.startsWith("edit")) {
            return "修改";
        } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
            return "删除";
        } else if (methodName.startsWith("get") || methodName.startsWith("find") || methodName.startsWith("select")) {
            return "查询";
        } else if (methodName.startsWith("export")) {
            return "导出";
        } else {
            return "其他";
        }
    }
}